package com.tengju.user.domain.model.user;

import com.tengju.user.domain.model.login.UserType;
import com.tengju.user.domain.model.protocol.ProtocolType;
import com.tengju.user.domain.model.protocol.ProtocolVersion;
import com.tengju.user.domain.shared.DomainException;
import com.tengju.user.domain.shared.DomainExceptionCode;
import lombok.Value;
import lombok.experimental.NonFinal;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Value
public class UserInfo implements LoginDesc {

    static final String INTERNAL_AREA_CODE = "+86";
    /**
     * 用户id
     */
    @NonFinal
    UserId userId;

    /**
     * 用户idcode
     */
    @NonFinal
    UserIdCode idCode;

    /**
     * 区号
     */
    @NonFinal
    String areaCode;

    /**
     * 手机号（不加区号）
     */
    @NonFinal
    String mobile;

    /**
     * 手机号（加区号）
     */
    @NonFinal
    String wholePhoneNumber;

    /**
     * 姓名
     */
    @NonFinal
    String name;

    /**
     * 昵称
     */
    @NonFinal
    String nickName;

    /**
     * 星级身份
     */
    @NonFinal
    Integer starRole;

    /**
     * 星级等级
     */
    @NonFinal
    Integer starLevel;

    /**
     * 上级id
     */
    @NonFinal
    UserIdCode pidCode;

    /**
     * 国家
     */
    @NonFinal
    String country;

    /**
     * 城市
     */
    @NonFinal
    String city;

    /**
     * 性别
     */
    @NonFinal
    Sex sex;

    /**
     * 头像
     */
    @NonFinal
    String headImage;

    @NonFinal
    List<ProtocolVersion> protocolInfo;

    /**
     * abm level
     */
    @NonFinal
    Integer abmLevel;

    public UserInfo(String areaCode, String mobile, String nickName, Integer starRole, Integer starLevel, Sex sex, String headImage) {
        this.areaCode = areaCode;
        this.mobile = mobile;
        this.nickName = nickName;
        this.starRole = (starRole == null ? StarRoleEnum.NONE.getCode() : starRole);
        this.starLevel = (starLevel == null ? StarLevelEnum.NONE.getCode() : starLevel);
        this.sex = sex;
        this.headImage = headImage;
        this.wholePhoneNumber = mobile;
        if (!INTERNAL_AREA_CODE.equals(areaCode)) {
            this.wholePhoneNumber = areaCode + mobile;
        }

    }

    public UserInfo(UserIdCode idCode) {
        this.idCode = idCode;
        this.starRole = (starRole == null ? StarRoleEnum.NONE.getCode() : starRole);
        this.starLevel = (starLevel == null ? StarLevelEnum.NONE.getCode() : starLevel);
    }


    public UserInfo(UserId userId, UserIdCode idCode, String areaCode, String mobile, String name, String nickName, Integer starRole, Integer starLevel, UserIdCode pidCode, String country, String city, Sex sex, String headImage, List<ProtocolVersion> protocolInfo) {
        this.idCode = idCode;
        this.pidCode = pidCode;
        this.userId = userId;
        this.areaCode = areaCode;
        this.mobile = mobile;
        this.name = name;
        this.nickName = nickName;
        this.starRole = (starRole == null ? StarRoleEnum.NONE.getCode() : starRole);
        this.starLevel = (starLevel == null ? StarLevelEnum.NONE.getCode() : starLevel);
        this.country = country;
        this.city = city;
        this.sex = sex;
        this.headImage = headImage;
        this.protocolInfo = protocolInfo;
        this.wholePhoneNumber = mobile;
        if (areaCode != null && !INTERNAL_AREA_CODE.equals(areaCode)) {
            this.wholePhoneNumber = areaCode + mobile;
        }
    }
    public UserInfo(UserIdCode idCode,UserIdCode parentIdCode){
        this.idCode=idCode;
        this.pidCode=parentIdCode;
    }

    public void updateStar(Integer targetStarRole, Integer targetStarLevel) {
        this.starLevel = targetStarLevel;
        this.starRole = targetStarRole;
    }

    public UserInfo(UserIdCode idCode, String areaCode, String mobile, String name, String nickName, Integer starRole, Integer starLevel, UserIdCode pidCode, String country, String city, Sex sex, String headImage,String wholePhoneNumber) {
        this.idCode = idCode;
        this.pidCode = pidCode;
        this.areaCode = areaCode;
        this.mobile = mobile;
        this.name = name;
        this.nickName = nickName;
        this.starRole = starRole;
        this.starLevel = starLevel;
        this.country = country;
        this.city = city;
        this.sex = sex;
        this.headImage = headImage;
        this.wholePhoneNumber = wholePhoneNumber;
    }


    public UserInfo(UserIdCode idCode, String areaCode, String mobile, String name, String nickName, Integer starRole, Integer starLevel, UserIdCode pidCode, String country, String city, Sex sex, String headImage,String wholePhoneNumber,Integer abmLevel) {
        this.idCode = idCode;
        this.pidCode = pidCode;
        this.areaCode = areaCode;
        this.mobile = mobile;
        this.name = name;
        this.nickName = nickName;
        this.starRole = starRole;
        this.starLevel = starLevel;
        this.country = country;
        this.city = city;
        this.sex = sex;
        this.headImage = headImage;
        this.wholePhoneNumber = wholePhoneNumber;
        this.abmLevel = abmLevel;
    }

    public UserInfo(UserId userId, UserIdCode idCode, String areaCode, String mobile, String name, String nickName, Integer starRole, Integer starLevel, UserIdCode pidCode, String country, String city, Sex sex, String headImage,String wholePhoneNumber,Integer abmLevel) {
        this.userId = userId;
        this.idCode = idCode;
        this.pidCode = pidCode;
        this.areaCode = areaCode;
        this.mobile = mobile;
        this.name = name;
        this.nickName = nickName;
        this.starRole = starRole;
        this.starLevel = starLevel;
        this.country = country;
        this.city = city;
        this.sex = sex;
        this.headImage = headImage;
        this.wholePhoneNumber = wholePhoneNumber;
        this.abmLevel = abmLevel;
    }

    public boolean isStar() {
        StarRoleEnum role = StarLevelEnum.getStarRoleCodeByLevel(this.starLevel);
        return !StarRoleEnum.NONE.equals(role);
    }

    public void completeInfo(String wholePhoneNumber, String name, String nickName, UserIdCode pIdCode) {
        this.wholePhoneNumber = wholePhoneNumber;
        this.name = name;
        this.nickName = nickName;
        this.pidCode = pIdCode;
    }


    public UserIdCode decryptIdCode() {
        if (idCode != null) {
            return new UserIdCode((idCode.getValue() >> 16) - 202111);
        }
        return null;
    }

    public UserIdCode decryptPidCode() {
        if (pidCode != null) {
            return new UserIdCode((pidCode.getValue() >> 16) - 202111);
        }
        return null;
    }

    public void storeUserId(UserId userId) {
        this.userId = userId;
    }

    @Override
    public long getId() {
        if (userId == null) {
            return 0;
        }
        return userId.getValue();
    }

    @Override
    public UserType getUserType() {
        return UserType.USER;
    }

    @Override
    public UserIdCode getUserIdCode() {
        return idCode;
    }

    public Map<ProtocolType, ProtocolVersion> protocolInfoMap() {

        if (CollectionUtils.isEmpty(protocolInfo)) {
            return new EnumMap<>(ProtocolType.class);
        }

        return protocolInfo.stream().collect(Collectors.toMap(ProtocolVersion::getProtocolType, Function.identity()));
    }


    public void storeProtocolInfo(Map<ProtocolType, ProtocolVersion> protocolVersionMap) {
        this.protocolInfo = new ArrayList<>(protocolVersionMap.values());
    }

    public boolean isInternalPhone() {
        return INTERNAL_AREA_CODE.equals(areaCode);
    }

    public void changeNickname(String newName) throws UnsupportedEncodingException {
        if (StringUtils.isEmpty(newName)) {
            throw DomainException.error(DomainExceptionCode.INVALID_DATA, "nickname is empty");
        }
        if (newName.getBytes("GB2312").length > 32) {
            throw DomainException.error(DomainExceptionCode.INVALID_DATA, "昵称最多32个字符16个汉字");
        }
        this.nickName = newName;
    }

    public void changeHeadImage(String headImage) {
        if (StringUtils.isEmpty(headImage)) {
            throw DomainException.error(DomainExceptionCode.INVALID_DATA, "headImage is empty");
        }
        this.headImage = headImage;
    }


    public boolean showSettleData() {

        return !StarRoleEnum.NONE.getCode().equals(this.getStarRole());

    }


    public String getWholePhone() {

        if (StringUtils.isBlank(mobile)) {
            return "";
        }

        return mobile.startsWith("+") ? mobile : areaCode + mobile;
    }

    public void removeAreaCode() {
        if (StringUtils.isEmpty(areaCode) || StringUtils.isEmpty(mobile)) {
            throw DomainException.error(DomainExceptionCode.INVALID_DATA,"区号或手机号为空");
        }
        this.mobile = mobile.substring(areaCode.length());
    }

    public boolean isMeetClub() {
        return starLevel.equals(StarLevelEnum.SEC.getCode()) ||
                starLevel.equals(StarLevelEnum.EEC.getCode());
    }

    public void changeMobile(String areaCode,String mobile) {
        this.areaCode = areaCode;
        this.mobile = mobile;
        this.wholePhoneNumber = mobile;
        if (!INTERNAL_AREA_CODE.equals(areaCode)) {
            this.wholePhoneNumber = areaCode + mobile;
        }
    }

    public StarLevelEnum targetLevel() {

        if (starLevel == null) {
            return StarLevelEnum.CITY_STAR_ONE;
        }

        switch (StarLevelEnum.parseByCode(starLevel)) {
            case NONE:
                return StarLevelEnum.CITY_STAR_ONE;
            case CITY_STAR_ONE:
                return StarLevelEnum.CITY_STAR_TWO;
            case CITY_STAR_TWO:
                return StarLevelEnum.CITY_STAR_THREE;
            case CITY_STAR_THREE:
                return StarLevelEnum.CITY_STAR_FOUR;
            case CITY_STAR_FOUR:
                return StarLevelEnum.EC;
            case EC:
                return StarLevelEnum.SEC;
            case SEC:
                return StarLevelEnum.EEC;
            default:
                return null;
        }
    }

    public StarLevelEnum starLevel() {
        return StarLevelEnum.parseByCode(starLevel);
    }

    /**
     * 后台统一展示昵称
     * 显示昵称，如果没有使用“用户”+手机号后四位
     * @return
     */
    public String getBackNickName() {
        if (StringUtils.isNotEmpty(nickName)) {
            return nickName;
        }
        if (StringUtils.isNotEmpty(mobile) && mobile.length() >= 4) {
            return "用户" + mobile.substring(mobile.length()-4);
        }
        return "";
    }
}
